﻿using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Threading;

namespace sinetd.Protocols.NetRemoting
{
    public class Protocol : BaseProtocol, IProtocol
    {
        public static AcceptClientHandler tmpAcceptClient;

        public void OnAcceptClient()
        {
            if (tmpAcceptClient != null)
            {
                if (this.cfg.GetBoolean("isServer"))
                {
                    StartThread(() =>
                    {
                        tmpAcceptClient(Protocol.prot);
                    });
                }
            }
        }

        private TcpServerChannel ServerChannel;
        private TcpClientChannel TcpChannel;
        private new string id;
        private static IProtocol prot;

        public override void ConfigDefault()
        {
            cfg.SetDefault("isServer", "false");
            cfg.SetDefault("SharedObject", "SharedObject.rem");
        }

        public override void ConfigChanged()
        {
            this.cfg.SetString("SharedObject", "SharedObject" + cfg.GetInt32("port"));
            base.ConfigChanged();
        }

        public Protocol() : base("NetRemoting") { }

        public Protocol(string config, string id)
            : base("NetRemoting", id)
        {
            this.Config = config;
        }

        public void Bind(AcceptClientHandler AcceptClient)
        {
            tmpAcceptClient = AcceptClient;

            ServerChannel = new TcpServerChannel(this.cfg.GetString("SharedObject"), this.cfg.GetInt32("port"));
            ChannelServices.RegisterChannel(ServerChannel, false);

            RemotingConfiguration.RegisterWellKnownServiceType(typeof(sinetd.Protocols.NetRemoting.Protocol), this.cfg.GetString("SharedObject"), WellKnownObjectMode.Singleton);

            Protocol.prot = this;
        }

        public bool Connect()
        {
            try
            {
                TcpChannel = new TcpClientChannel();
                ChannelServices.RegisterChannel(TcpChannel, false);

                WellKnownClientTypeEntry remoteType = new WellKnownClientTypeEntry(typeof(sinetd.Protocols.NetRemoting.Protocol), "tcp://localhost:" + this.cfg.GetInt32("port") + "/" + this.cfg.GetString("SharedObject"));
                RemotingConfiguration.RegisterWellKnownClientType(remoteType);

                prot = (IProtocol)Activator.GetObject(typeof(IProtocol), "tcp://localhost:" + this.cfg.GetInt32("port") + "/" + this.cfg.GetString("SharedObject"));
                prot.Config = this.Config + ";isServer=true";

                ((Protocol)Protocol.prot).OnAcceptClient();

                return true;
            }
            catch
            {
                return false;
            }
        }

        public void Close()
        {
            if (this.cfg.GetBoolean("isServer"))
            {
                ChannelServices.UnregisterChannel(ServerChannel);
            }
        }

        private static string toRecv = null;

        public void Send(string msg)
        {
            if (this.cfg.GetBoolean("isServer"))
            {
                if (toRecv != null)
                {
                    while (toRecv != null) ;
                }
                toRecv = msg;
                Thread.Sleep(1);
            }
            else
            {
                prot.Send(msg);
            }
        }

        public string Recv()
        {
            if (this.cfg.GetBoolean("isServer"))
            {
                if (toRecv == null)
                {
                    while (toRecv == null) ;
                }
                string tmp = toRecv;
                toRecv = null;
                return tmp;
            }
            else
            {
                return prot.Recv();
            }
        }

        public int c = 0;
    }
}
